package com.yingside.reflection;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Properties;

public class Test_Reflection {

	public static void main(String[] args){
		//获取对象
		//1.编译器已经知道名字
		Class c1 = TestReflection.class;
		//2.已经的到类的实例对象
		TestReflection tf = new TestReflection();
		Class c2 = tf.getClass();
		//3.通过运行期获取名字
		//Class c3 = Class.forName("com.yingside.reflection.TestReflection");
		//读取属性文件，在运行期获取对象
		Class c3 = null;
		Properties p = new Properties();
		
		try {
			FileInputStream fis = new FileInputStream("prop.properties");
			p.load(fis);
			String className = p.getProperty("className");
			c3 = Class.forName(className);


			
			fis.close();
		} catch (IOException e) {

			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//==========================================================================================		
		//获取指定包名
		String package1 = c1.getPackage().getName();
		String package3 = c3.getPackage().getName();
		
		System.out.println(package1 + "   " + package3);
		
//==========================================================================================		
		
		//获取类权限修饰符
		int mod = c3.getModifiers();
		String modifier = Modifier.toString(mod);
		System.out.println("类的权限修饰符:" + modifier);
		
		//获取完整类名
		String className = c3.getName();
		System.out.println("完整类名:" + className);
		
		//获取父类
		Class superClass = c3.getSuperclass();
		System.out.println(Modifier.toString(superClass.getModifiers()) 
				+ " class " + superClass.getName());
		
		//获取实现接口
		Class [] interfaces = c3.getInterfaces();
		for(Class t : interfaces){
			System.out.println(Modifier.toString(t.getModifiers()) 
					+ " interface " + t.getName());
		}
//S==========================================================================================
		
		//获取成员变量
		Field [] fds = c3.getDeclaredFields();
		
		for(Field field : fds){
			//获取每个字段的访问修饰符
			String mods = Modifier.toString(field.getModifiers());
			//获取每个字段的类型
			Class type = field.getType();
			//得到类型名
			String typeName = type.getName();
			//得到字段名
			String fieldName = field.getName();
			
			//如果是数组，需要特殊处理一下
			if(type.isArray()){
				typeName = type.getComponentType().getName() + "[]";
			}
			
			System.out.println(mods + " " + typeName + " " + fieldName);
		}
		
//==========================================================================================	
		
		//获取构造方法
		Constructor [] constructors = c3.getDeclaredConstructors();
		for(Constructor constructor : constructors){
			//获取构造方法名
			String consName = constructor.getName();
			//获取构造方法访问修饰符
			String consModifier = Modifier.toString(constructor.getModifiers());
			
			//获取构造方法中的参数
			Class [] paramTypes = constructor.getParameterTypes();
			
			System.out.print(consModifier + " " + consName + "(");
			//循环所有参数类型
			for(int i=0;i<paramTypes.length;i++){
				//如果第一个参数后需要加上逗号
				if(i > 0){
					System.out.print(", ");
				}
				//如果是数组需要特殊处理
				if(paramTypes[i].isArray()){
					System.out.print(paramTypes[i].getComponentType().getName() + "[]");
				}else{
					System.out.print(paramTypes[i].getName());
				}
			}
			System.out.println(")");
		}
		
//==========================================================================================	
		
		//获取成员方法
		Method [] methods = c3.getDeclaredMethods();
		//遍历所有成员方法
		for(Method m : methods){
			//获取访问修饰符
			String mMod = Modifier.toString(m.getModifiers());
			//获取返回值类型
			Class mType = m.getReturnType();
			
			String returnType = "";
			if(mType.isArray()){
				returnType = mType.getComponentType().getName() + "[]";
			}else{
				returnType = mType.getName();
			}
			
			String mName = m.getName();
			
			System.out.print(mMod + " " + returnType + " " + mName + "(");
			
			//获取参数列表
			Class [] paramTypes = m.getParameterTypes();
			for(int i=0;i<paramTypes.length;i++){
				if(i > 0){
					System.out.print(", ");
				}
				if(paramTypes[i].isArray()){
					System.out.print(paramTypes[i].getComponentType().getName() + "[]");
				}else{
					System.out.print(paramTypes[i].getName());
				}
			}
			
			System.out.println(")");
		}
//==========================================================================================
		//反射调用方法，可以通过Method类的invoke方法实现动态方法的调用
		//public Object invoke(Object obj,Object...args)
		//第一个参数代表对象
		//第二个参数开始，代表执行方法上的参数
		//若反射要调用类的某个私有方法,可以在这个私有方法对应的Method对象上先调用setAccessible(true)
		
		//之前已经获取了c3的class对象，首先获得实例化对象，然后对变量直接赋值查看结果
		try {
			//通过newInstance()方法获取实例化对象
			//但是直接通过这种方法无法访问带参数的构造方法
			TestReflection trf = (TestReflection)c3.newInstance();
			trf.name = "张三";
			trf.password = "123456";
			trf.score = new int[3];
			trf.score[0] = 90;
			trf.score[1] = 91;
			trf.score[2] = 92;
			System.out.println("name=====" + trf.name);
			
			//通过构造方法同样可以实例化对象
			//要调用带参数的构造方法生成对象，可以使用下面的方式
			Constructor cons = c3.getConstructor(new Class[]{String.class,String.class});
			Object obj = cons.newInstance(new Object[]{"zhangsan","abcdefg"});
			TestReflection trf2 = ((TestReflection)obj);
			System.out.println("trf2-name=====" + trf2.name);
			System.out.println("trf2-password=====" + trf2.password);

			//带数组的构造方法
			Constructor cons1 = c1.getConstructor(new Class[]{String.class,String.class,int[].class});
			Object o1 = cons1.newInstance(new Object[]{"张三","11111",new int[]{1,2,3}});
			TestReflection tf2 = (TestReflection)o1;
			System.out.println(tf2.name);
			for(Integer i:tf2.score){
				System.out.println(i);
			}
			
			//注意:getDeclaredMethod()获取的是类自身声明的所有方法，
			//包括public，protected和private方法
			
			//getMethod()获取的是类的所有共有方法，
			//意思是包括自身所有的public方法。以及从父类继承，从接口实现的所有public方法
			
			//通过反射调用方法
			Method method1 = c3.getDeclaredMethod("setName", String.class);
			method1.invoke(trf, "李四");
			
			//通过反射调用带数组参数的方法
			Method method2 = c3.getDeclaredMethod("setScore", new Class[]{int[].class});
			int [] nums = {1,2,3};
			method2.invoke(trf,new Object[]{nums});
			
			//通过反射调用private修饰的方法
			Method method3 = c3.getDeclaredMethod("setPassword", String.class);
			method3.setAccessible(true);
			method3.invoke(trf,"aabbccdd");
			
			System.out.println("name=====" + trf.name);
			System.out.println("scores====" + trf.score[0]);
			System.out.println("password=====" + trf.password);
			
			
			
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
